﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web.Http;
using Sustainalytics.Utils;
using Sustainalytics.Utils.WebApi.ErrorCodes;
using Sustainalytics.Entities;
using System.Configuration;
using System.IO;
using Sustainalytics.Claims.Service.Model;
using Newtonsoft.Json;
using Sustainalytics.DataLayer;
using System.Web.Http.Cors;

namespace Sustainalytics.Claims.Service.Controllers
{
    //[AutoInvalidateCacheOutput]
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [RoutePrefix("api/v1/claims")]
    public class ClaimsController : ApiController, IClaimsController
    {
        static IClaimsChecker _claimsChecker;
        private readonly IAccountsRepository _accountsReposiory;
        private ExcelClaimsModifier claimsModifier;

        public ClaimsController(IClaimsChecker claimsChecker, IAccountsRepository accountsRepository)
        {
            _claimsChecker = claimsChecker;
            _accountsReposiory = accountsRepository;

        }
 
        [Route("")]
        public async Task<HttpResponseMessage> Post()
        {
            try
            {
                if (!Request.Content.IsMimeMultipartContent())
                {
                    Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
                }
                
                var result = await Request.Content.ReadAsMultipartAsync( GetMultipartProvider());
                
                var uploadedFileName = new FileInfo(result.FileData.First().LocalFileName);

                byte[] dataFile = File.ReadAllBytes(uploadedFileName.FullName);

                var uploadObj = GetFormData<ClaimsUploadDto>(result);
                var form = (ClaimsUploadDto)uploadObj;

                claimsModifier = new ExcelClaimsModifier(new OperationClaimsRetriever(), _accountsReposiory.TryGetAccountById);

                var importLogs = ImportLogsDto.CreateComplete(claimsModifier.ParseExcel(dataFile, form.ProcessAllContent));

                return Request.CreateResponse(HttpStatusCode.OK, new { importLogs });

            }
            catch (Exception ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError,
                                              new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
            }
        }

        [Route("")]
        public HttpResponseMessage Get()
        {
            try
            {
                var userName = this.GetCurrentUserClaims() as ClaimsPrincipal;

                List<ResourceMap> resources = _claimsChecker.GetUIResources(userName).ToList();

                // add admin resource maps if any associated to current username
                this.AddAdminResourceMap(userName.Identity.Name, resources);

                List<UIResourceDto> allowedResources = new List<UIResourceDto>();

                foreach (ResourceMap resource in resources)
                {
                    allowedResources.Add(UIResourceDto.Create(resource));
                }

                return Request.CreateResponse(HttpStatusCode.OK, allowedResources);
            }
            catch (ArgumentException)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
            catch (Exception)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        [Route("lastSyncDate")]
        public HttpResponseMessage GetLastSyncDate()
        {
            try
            {
                var dt = _accountsReposiory.GetLastSyncDate(SyncType.Claim);
                return Request.CreateResponse(HttpStatusCode.OK, dt);
            }
            catch (Exception)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }


        private void AddAdminResourceMap(string userName, List<ResourceMap> resources)
        {
            // adjust username for searching
            var userNameAdjusted = userName.Trim().ToLowerInvariant();

            // get comma sepparated admin user names
            string adminUsersSetting = ConfigurationManager.AppSettings["adminUsers"];

            if (string.IsNullOrEmpty(adminUsersSetting))
            {
                return;
            }

            string[] adminUsersLst = adminUsersSetting.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string adminUser in adminUsersLst)
            {
                // adjust admin user for searching
                var adminUserAdjusted = adminUser.Trim().ToLowerInvariant();

                if (adminUserAdjusted == userNameAdjusted)
                {
                    resources.Add(new ResourceMap
                    {
                        Permission = "Administrator",
                        Value = "GET",
                        Resource = new Resource
                        {
                            Name = "api/v1/admin"
                        },
                        Parameters = new List<ResourceParameters>()
                    });

                    break;
                }
            }
        }


        private MultipartFormDataStreamProvider GetMultipartProvider()
        {
            var uploadFolder = @"TempFileUploads";
            var root = uploadFolder;
            Directory.CreateDirectory(root);
            return new MultipartFormDataStreamProvider(root);
        }

        private object GetFormData<T>(MultipartFormDataStreamProvider result)
        {
            if (result.FormData.HasKeys())
            {
                var unescapedFormData = Uri.UnescapeDataString(stringToUnescape: result.FormData
                    .GetValues(0).FirstOrDefault() ?? String.Empty);
                if (!String.IsNullOrEmpty(unescapedFormData))
                    return JsonConvert.DeserializeObject<T>(unescapedFormData);
            }
            return null;
        }
    }
}
